package task

import (
	"context"
	"errors"
	"smart-flow/server/config"
	"smart-flow/server/logger"
	"smart-flow/server/redis"
	"strings"

	"go.uber.org/zap"

	redisLib "github.com/go-redis/redis/v8"
)

var (
	rdbNode1      *redisLib.Client // 10.19.169.113
	rdbNode2      *redisLib.Client // 10.19.129.140
	rdbNode3      *redisLib.Client // 10.19.197.188
	rdbCenter     *redisLib.Client
	dataCleanChan = make(chan string, 1000)
)

func StartCheckAlign() {
	connectExternalRedis()
	doCheckAlignClient()
	go dataAlignCleanScan()
	dataAlignCleanWorker()
}

func connectExternalRedis() {
	rdbNode1 = redisLib.NewClient(&redisLib.Options{
		Addr:     "10.19.169.113:6379",
		Password: "",
		DB:       0,
		PoolSize: 10,
	})
	rdbNode2 = redisLib.NewClient(&redisLib.Options{
		Addr:     "10.19.129.140:6379",
		Password: "",
		DB:       0,
		PoolSize: 10,
	})
	rdbNode3 = redisLib.NewClient(&redisLib.Options{
		Addr:     "10.19.197.188:6379",
		Password: "",
		DB:       0,
		PoolSize: 10,
	})
	rdbCenter = redisLib.NewClient(&redisLib.Options{
		Addr:     "10.19.158.116:6379",
		Password: "",
		DB:       0,
		PoolSize: 10,
	})
}

func doCheckAlignClient() {
	var nextCursor uint64 = 0
	var keys []string
	var err error
	var exist bool
	var deathUids []string
	for {
		keys, nextCursor, err = redis.RDB.HScan(context.Background(), config.FlowClientKey, nextCursor, "*", 1000).Result()
		if err != nil {
			if errors.Is(err, redisLib.Nil) {
				return
			}
			logger.Logger.Error("[任务] Checker操作Redis异常", zap.Error(err))
			return
		}
		for i := 0; i < len(keys); i += 2 {
			uid := keys[i]
			if !strings.HasPrefix(uid, "whaley") {
				continue
			}
			exist, err = rdbNode1.HExists(context.Background(), "client_info", uid).Result()
			if err != nil {
				logger.Logger.Error("[任务] Checker操作Redis异常", zap.Error(err))
				return
			}
			if exist {
				continue
			}
			exist, err = rdbNode2.HExists(context.Background(), "client_info", uid).Result()
			if err != nil {
				logger.Logger.Error("[任务] Checker操作Redis异常", zap.Error(err))
				return
			}
			if exist {
				continue
			}
			exist, err = rdbNode3.HExists(context.Background(), "client_info", uid).Result()
			if err != nil {
				logger.Logger.Error("[任务] Checker操作Redis异常", zap.Error(err))
				return
			}
			if exist {
				continue
			}
			deathUids = append(deathUids, uid)
		}
		if nextCursor == 0 {
			break
		}
	}
	logger.Logger.Info("[任务] 检测到死亡客户端", zap.Int("deathCount", len(deathUids)))
	for i := 0; i < len(deathUids); i += 500 {
		redis.RDB.HDel(context.Background(), config.FlowClientKey, deathUids[i:min(len(deathUids), i+500)]...)
	}
}

func dataAlignCleanScan() {
	defer close(dataCleanChan)
	var nextCursor uint64 = 0
	var data []string
	var err error
	for {
		data, nextCursor, err = redis.RDB.HScan(context.Background(), config.FlowClientKey, nextCursor, "*", 1000).Result()
		if err != nil {
			if errors.Is(err, redisLib.Nil) {
				return
			}
			logger.Logger.Error("[任务] Checker操作Redis异常", zap.Error(err))
			return
		}
		for i := 0; i < len(data); i += 2 {
			uid := data[i]
			dataCleanChan <- uid
		}
		if nextCursor == 0 {
			return
		}
	}
}

func dataAlignCleanWorker() {
	for uid := range dataCleanChan {
		exist, err := rdbCenter.HExists(context.Background(), "client_host_info", uid).Result()
		if err != nil {
			logger.Logger.Error("[任务] Checker操作Redis异常", zap.Error(err))
			return
		}
		if !exist {
			redis.RDB.HDel(context.Background(), "client", uid)
		}
	}
}
